/*
 * Copyright (c) 2002-2012 Alibaba Group Holding Limited.
 * All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.alibaba.toolkit.util.collection;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;

/**
 * <p>
 * 一个集合的实现, 实现了<code>Set</code>接口.
 * </p>
 * <p>
 * 这个集合在内部使用<code>ArrayHashMap</code>保存集合中的元素, 因而具有以下特性:
 * </p>
 * <ul>
 * <li>不同于<code>HashMap</code>, 集合中元素的顺序是确定的</li>
 * <li>和<code>ArrayHashMap</code>一样, 没有进行任何<code>synchronized</code>操作</li>
 * </ul>
 *
 * @author Michael Zhou
 * @version $Id: ArrayHashSet.java,v 1.1 2003/07/03 07:26:15 baobao Exp $
 * @see ArrayHashMap
 */
public class ArrayHashSet extends AbstractSet implements Set, Cloneable, Serializable {
    /*
     * ==========================================================================
     * ==
     */
    /* 常量 */
    /*
     * ==========================================================================
     * ==
     */

    /** 表示内部hash表的值. */
    private static final Object PRESENT = new Object();

    /*
     * ==========================================================================
     * ==
     */
    /* 成员变量 */
    /*
     * ==========================================================================
     * ==
     */

    /** 内部的hash表. */
    protected transient ArrayHashMap map;

    /*
     * ==========================================================================
     * ==
     */
    /* 构造函数 */
    /*
     * ==========================================================================
     * ==
     */

    /** 创建一个空的集合. 使用指定的默认的初始容量(16)和默认的负载系数(0.75). */
    public ArrayHashSet() {
        map = new ArrayHashMap();
    }

    /**
     * 创建一个空的集合. 使用指定的初始阈值和默认的负载系数(0.75).
     *
     * @param initialCapacity 初始容量.
     */
    public ArrayHashSet(int initialCapacity) {
        map = new ArrayHashMap(initialCapacity);
    }

    /**
     * 创建一个空的集合. 使用指定的初始容量和负载系数.
     *
     * @param initialCapacity 初始容量
     * @param loadFactor      负载系数.
     */
    public ArrayHashSet(int initialCapacity, float loadFactor) {
        map = new ArrayHashMap(initialCapacity, loadFactor);
    }

    /**
     * 创建一个空的集合, 并复制指定的<code>Collection</code>的所有项到这个集合中. 使用默认的负载系数(0.75).
     *
     * @param collection 要复制的<code>Collection</code>
     */
    public ArrayHashSet(Collection collection) {
        map = new ArrayHashMap(Math.max((int) (collection.size() / .75f) + 1, 16));
        addAll(collection);
    }

    /*
     * ==========================================================================
     * ==
     */
    /* 实现Set接口的方法 */
    /*
     * ==========================================================================
     * ==
     */

    /**
     * 返回集合中entry的个数.
     *
     * @return 集合中的entry数.
     */
    @Override
    public int size() {
        return map.size();
    }

    /**
     * 判断是否为空的集合.
     *
     * @return 如果为空(<code>size() == 0</code>), 则返回<code>true</code>.
     */
    @Override
    public boolean isEmpty() {
        return map.isEmpty();
    }

    /**
     * 如果集合中包含指定值, 则返回<code>true</code>.
     *
     * @param object 测试指定值是否存在.
     * @return 如果指定值存在, 则返回<code>true</code>.
     */
    @Override
    public boolean contains(Object object) {
        return map.containsKey(object);
    }

    /**
     * 将指定的值加入到集合中.
     *
     * @param object 要加入的值
     * @return 如果集合中已经存在此值, 则返回<code>false</code>. 否则返回<code>true</code>.
     */
    @Override
    public boolean add(Object object) {
        return map.put(object, PRESENT) == null;
    }

    /**
     * 将指定值从集合中删除(如果该值存在的话).
     *
     * @param object 要被删除的值
     * @return 如果被删除的值原来不存在, 则返回<code>false</code>, 否则返回<code>true</code>
     */
    @Override
    public boolean remove(Object o) {
        return map.remove(o) == PRESENT;
    }

    /** 清除集合中的所有对象. */
    @Override
    public void clear() {
        map.clear();
    }

    /**
     * 取得集合中所有项的遍历器.
     *
     * @return 集合中所有项的遍历器
     */
    @Override
    public Iterator iterator() {
        return map.keySet().iterator();
    }

    /*
     * ==========================================================================
     * ==
     */
    /* 复制方法(Clonable接口) */
    /*
     * ==========================================================================
     * ==
     */

    /**
     * &quot;浅&quot;拷贝集合, 集合中的对象本身并不被复制.
     *
     * @return 被复制的集合.
     */
    @Override
    public Object clone() {
        try {
            ArrayHashSet newSet = (ArrayHashSet) super.clone();

            newSet.map = (ArrayHashMap) map.clone();

            return newSet;
        } catch (CloneNotSupportedException e) {
            throw new InternalError(); // 不支持clone(不可能).
        }
    }

    /*
     * ==========================================================================
     * ==
     */
    /* 序列化 */
    /*
     * ==========================================================================
     * ==
     */

    /** 序列化版本号. */
    private static final long serialVersionUID = -5024744406713321676L;

    /**
     * 从输入流中重建集合(也就是反序列化).
     *
     * @param is 输入流
     * @throws IOException            输入流异常
     * @throws ClassNotFoundException 类未找到
     */
    private synchronized void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
        is.defaultReadObject();

        int capacity = is.readInt();
        float loadFactor = is.readFloat();

        map = new ArrayHashMap(capacity, loadFactor);

        int size = is.readInt();

        for (int i = 0; i < size; i++) {
            Object e = is.readObject();

            map.put(e, PRESENT);
        }
    }

    /**
     * 将集合的状态保存到输出流中(也就是序列化).
     *
     * @param os 输出流
     * @throws IOException 输出流异常
     */
    private synchronized void writeObject(ObjectOutputStream os) throws IOException {
        os.defaultWriteObject();

        os.writeInt(map.getCapacity());
        os.writeFloat(map.getLoadFactor());

        os.writeInt(map.size());

        for (Iterator i = map.keySet().iterator(); i.hasNext(); ) {
            os.writeObject(i.next());
        }
    }
}
